package com.tdk.mybatisplus.demo.common.config;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import com.google.common.eventbus.Subscribe;

import com.tdk.mybatisplus.demo.common.entity.EventBusUser;
import com.tdk.mybatisplus.demo.common.entity.WebSocketMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;

import static com.tdk.mybatisplus.demo.common.entity.WebSocketResultEnum.REPLY_MESSAGE;


/**
 * <p>
 * webSocket
 * </p>
 *
 * @author: taodingkai
 * @modified:
 * @since: 2022/8/24 10:25
 */
@Component
@ServerEndpoint("/websocket")
@Slf4j
public class WebSocketServerEndpoint implements EventBusUser {
    @Autowired
    private ApplicationContext applicationContext;
    
    public static final Map<String,Session> SESSION_MAP= Maps.newConcurrentMap();

    /**
     * <p>
     * 注册eventBus
     * </p>
     *
     * @author: taodingkai
     * @since: 2022/8/16 16:23 
     */
    @PostConstruct
    @Override
    public void register() {
        getDefaultEventBus().register(applicationContext.getBean(WebSocketServerEndpoint.class));
    }
    
    /**
     * <p>
     * 连接
     * </p>
     *
     *
     * @param session  
     * @author: taodingkai
     * @since: 2022/8/24 15:16 
     */
    @OnOpen
    public void onOpen(Session session) {
        log.info("[{}]连接成功",session.getId());
        SESSION_MAP.put(session.getId(),session);
    }

    /**
     * <p>
     * 关闭
     * </p>
     *
     *
     * @param session  
     * @author: taodingkai
     * @since: 2022/8/24 15:17 
     */
    @OnClose
    public void onClose(Session session) {
        log.info("[{}]连接关闭",session.getId());
        SESSION_MAP.remove(session.getId());
    }

    /**
     * <p>
     * 收消息
     * </p>
     *
     *
     * @param session
     * @param text  
     * @author: taodingkai
     * @since: 2022/8/24 15:17 
     */
    @OnMessage
    public void onMessage(Session session, String text) throws IOException {
        log.info("[{}]收到消息:{}",session.getId(),text);
        sendMessage(session,REPLY_MESSAGE.toWebSocketMessage(StrUtil.format("[{}]服务端已经收到消息[{}]",session.getId(),text)));
    }
    
    /**
     * <p>
     * 遇到错误
     * </p>
     *
     *
     * @param session
     * @param t  
     * @author: taodingkai
     * @since: 2022/8/24 15:17 
     */
    @OnError
    public void onError(Session session,Throwable t) {
        log.error("[{}]连接出错",session.getId(),t);
        SESSION_MAP.remove(session.getId());
    }
    
    /**
     * <p>
     * 发送消息
     * </p>
     *
     *
     * @param session
     * @param message  
     * @author: taodingkai
     * @since: 2022/8/24 15:18 
     */
    public <T> void sendMessage(Session session, WebSocketMessage<T> message){
        try {
            session.getBasicRemote().sendText(new ObjectMapper().writeValueAsString(message));
            log.info("发送消息[{}]给[{}]成功",JSON.toJSONString(message));
        } catch (IOException e) {
            log.error("发送消息[{}]给[{}]失败",JSON.toJSONString(message),session.getId(),e);
        }
    }

    /**
     * <p>
     * 广播
     * </p>
     *
     *
     * @param message  
     * @author: taodingkai
     * @since: 2022/8/24 15:19 
     */
    @Subscribe
    public <T> void sendMessage2AllClient(WebSocketMessage<T> message){
        SESSION_MAP.forEach((key,session)->{
            sendMessage(session,message);
        });
    }
}
